﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Subjects;
using MyWpf.Common.Common;

namespace MyWpf.Common.MessageBroker
{
    public class BroadcastContextStrategy : IContextStrategy
    {
        private readonly Dictionary<Type, object> _observersByType = new Dictionary<Type, object>();
        private readonly Dictionary<Type, List<Type>> _providersByType = new Dictionary<Type, List<Type>>();
        public BroadcastContextStrategy()
        {
            ContextType = typeof(object);
        }

        public IDisposable RegisterProvider<T>(object provider, IObservable<T> contextObservable) where T : IContext
        {
            var typeofContext = typeof(T);
            var typeofProvider = provider.GetType();

            var providers = _providersByType.ValueOf(typeofContext);
            if (providers == null)
            {
                _providersByType.Add(typeofContext, new List<Type> { typeofProvider });
            }
            else
            {
                var resultType = providers.FirstOrDefault(x => x == typeofProvider);
                if (resultType == null)
                {
                    providers.Add(typeofProvider);
                }
            }

            return contextObservable.Subscribe(OnContextUpdated);
        }

        public IDisposable RegisterListener<T>(IObserver<T> contextObserver) where T : IContext
        {
            var typeofT = typeof(T);
            var subject = _observersByType.ValueOf(typeofT) as Subject<T>;

            if (subject == null)
            {
                subject = new Subject<T>();
                _observersByType.Add(typeofT, subject);
            }

            return subject.Subscribe(contextObserver);
        }

        public bool IsProvider<T>(Type providerType)
        {
            var typeofContext = typeof(T);
            var providers = _providersByType.ValueOf(typeofContext);
            return providers != null && providers.Any(provider => provider == providerType);
        }

        public Type ContextType { get; }

        private void OnContextUpdated<T>(T context)
        {
            var observers = _observersByType.ValueOf(typeof(T)) as Subject<T>;

            observers?.OnNext(context);
        }
    }
}
